// internal/api/handlers/vm_handler.go
package handlers

import (
	"io"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"

	"virt-manager-go/internal/domain"
)

// ConnectRequest 连接请求结构体
type ConnectRequest struct {
	URI      string             `json:"uri" binding:"required"`
	ReadOnly bool               `json:"read_only"`
	Auth     *domain.AuthConfig `json:"auth,omitempty"`
	TLS      *domain.TLSConfig  `json:"tls,omitempty"`
}

type VMHandler struct {
	vmService domain.VMService
	logger    *logrus.Logger
}

func NewVMHandler(vmService domain.VMService, logger *logrus.Logger) *VMHandler {
	return &VMHandler{
		vmService: vmService,
		logger:    logger,
	}
}

// ListVMs 列出虚拟机
//
//	@Summary	List virtual machines
//	@Tags		VM
//	@Param		connection_id	path	string	true	"Connection ID"
//	@Success	200				{array}	domain.VMInfo
//	@Router		/connections/{connection_id}/vms [get]
func (h *VMHandler) ListVMs(c *gin.Context) {
	connID := c.Param("connection_id")

	vms, err := h.vmService.ListVMs(c.Request.Context(), connID)
	if err != nil {
		h.logger.WithError(err).Error("Failed to list VMs")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"data":  vms,
		"count": len(vms),
	})
}

// GetVM 获取单个虚拟机
//
//	@Summary	Get virtual machine details
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Success	200				{object}	domain.VMInfo
//	@Router		/connections/{connection_id}/vms/{vm_name} [get]
func (h *VMHandler) GetVM(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")

	vm, err := h.vmService.GetVM(c.Request.Context(), connID, vmName)
	if err != nil {
		h.logger.WithError(err).Error("Failed to get VM")
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"data": vm})
}

// CreateVM 创建虚拟机
//
//	@Summary	Create a new virtual machine
//	@Tags		VM
//	@Param		connection_id	path		string					true	"Connection ID"
//	@Param		config			body		domain.VMCreateConfig	true	"VM Configuration"
//	@Success	201				{object}	domain.VMInfo
//	@Router		/connections/{connection_id}/vms [post]
func (h *VMHandler) CreateVM(c *gin.Context) {
	connID := c.Param("connection_id")

	var config domain.VMCreateConfig
	if err := c.ShouldBindJSON(&config); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
		return
	}

	// 验证至少有一种安装方式
	if config.InstallISO == "" && !config.InstallPXE && config.ImportDisk == "" && len(config.Disks) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "Must specify at least one installation method: install_iso, install_pxe, import_disk, or disks",
		})
		return
	}

	vm, err := h.vmService.CreateVM(c.Request.Context(), connID, &config)
	if err != nil {
		h.logger.WithError(err).Error("Failed to create VM")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"data": vm})
}

// StartVM 启动虚拟机
//
//	@Summary	Start a virtual machine
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Success	200				{object}	map[string]string
//	@Router		/connections/{connection_id}/vms/{vm_name}/start [post]
func (h *VMHandler) StartVM(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")

	if err := h.vmService.StartVM(c.Request.Context(), connID, vmName); err != nil {
		h.logger.WithFields(logrus.Fields{
			"connection_id": connID,
			"vm_name":       vmName,
			"error":         err.Error(),
		}).Error("Failed to start VM")

		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   err.Error(),
			"message": "Failed to start VM",
			"details": map[string]string{
				"connection_id": connID,
				"vm_name":       vmName,
			},
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "VM started successfully"})
}

// ShutdownVM 关闭虚拟机
//
//	@Summary	Shutdown a virtual machine
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Param		force			query		bool	false	"Force shutdown"
//	@Success	200				{object}	map[string]string
//	@Router		/connections/{connection_id}/vms/{vm_name}/shutdown [post]
func (h *VMHandler) ShutdownVM(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")
	force := c.Query("force") == "true"

	if err := h.vmService.ShutdownVM(c.Request.Context(), connID, vmName, force); err != nil {
		h.logger.WithError(err).Error("Failed to shutdown VM")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "VM shutdown initiated"})
}

// RebootVM 重启虚拟机
//
//	@Summary	Reboot a virtual machine
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Success	200				{object}	map[string]string
//	@Router		/connections/{connection_id}/vms/{vm_name}/reboot [post]
func (h *VMHandler) RebootVM(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")

	if err := h.vmService.RebootVM(c.Request.Context(), connID, vmName); err != nil {
		h.logger.WithError(err).Error("Failed to reboot VM")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "VM rebooted"})
}

// SuspendVM 暂停虚拟机
//
//	@Summary	Suspend a virtual machine
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Success	200				{object}	map[string]string
//	@Router		/connections/{connection_id}/vms/{vm_name}/suspend [post]
func (h *VMHandler) SuspendVM(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")
	if err := h.vmService.SuspendVM(c.Request.Context(), connID, vmName); err != nil {
		h.logger.WithError(err).Error("Failed to suspend VM")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "VM suspended successfully"})
}

// ResumeVM 恢复虚拟机
//
//	@Summary	Resume a virtual machine
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Success	200				{object}	map[string]string
//	@Router		/connections/{connection_id}/vms/{vm_name}/resume [post]
func (h *VMHandler) ResumeVM(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")
	if err := h.vmService.ResumeVM(c.Request.Context(), connID, vmName); err != nil {
		h.logger.WithError(err).Error("Failed to resume VM")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "VM resumed successfully"})
}

// DeleteVM 删除虚拟机
//
//	@Summary	Delete a virtual machine
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Param		remove_storage	query		bool	false	"Remove storage"
//	@Success	200				{object}	map[string]string
//	@Router		/connections/{connection_id}/vms/{vm_name} [delete]
func (h *VMHandler) DeleteVM(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")
	removeStorage := c.Query("remove_storage") == "true"

	if err := h.vmService.DeleteVM(c.Request.Context(), connID, vmName, removeStorage); err != nil {
		h.logger.WithError(err).Error("Failed to delete VM")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "VM deleted successfully"})
}

// CloneVM 克隆虚拟机
//
//	@Summary	Clone a virtual machine
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"Source VM Name"
//	@Success	201				{object}	map[string]string
//	@Router		/connections/{connection_id}/vms/{vm_name}/clone [post]
func (h *VMHandler) CloneVM(c *gin.Context) {
	connID := c.Param("connection_id")
	srcVM := c.Param("vm_name")

	var req struct {
		Name string `json:"name" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	if err := h.vmService.CloneVM(c.Request.Context(), connID, srcVM, req.Name); err != nil {
		h.logger.WithError(err).Error("Failed to clone VM")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"message": "VM cloned successfully", "name": req.Name})
}

// UpdateVM 更新虚拟机配置
//
//	@Summary	Update virtual machine configuration
//	@Tags		VM
//	@Param		connection_id	path		string			true	"Connection ID"
//	@Param		vm_name			path		string			true	"VM Name"
//	@Param		config			body		domain.VMConfig	true	"VM Configuration"
//	@Success	200				{object}	map[string]string
//	@Router		/connections/{connection_id}/vms/{vm_name} [patch]
func (h *VMHandler) UpdateVM(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")

	var config domain.VMConfig
	if err := c.ShouldBindJSON(&config); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	if err := h.vmService.UpdateVMConfig(c.Request.Context(), connID, vmName, &config); err != nil {
		h.logger.WithError(err).Error("Failed to update VM")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "VM updated successfully"})
}

// GetVMXML 获取虚拟机 XML
//
//	@Summary	Get virtual machine XML
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Success	200				{object}	map[string]string
//	@Router		/connections/{connection_id}/vms/{vm_name}/xml [get]
func (h *VMHandler) GetVMXML(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")

	xmlData, err := h.vmService.GetVMXML(c.Request.Context(), connID, vmName)
	if err != nil {
		h.logger.WithError(err).Error("Failed to get VM XML")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"xml": xmlData})
}

// GetVMMetrics 获取虚拟机性能指标
//
//	@Summary	Get virtual machine metrics
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Success	200				{object}	domain.VMMetrics
//	@Router		/connections/{connection_id}/vms/{vm_name}/metrics [get]
func (h *VMHandler) GetVMMetrics(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")

	metrics, err := h.vmService.GetVMMetrics(c.Request.Context(), connID, vmName)
	if err != nil {
		h.logger.WithError(err).Error("Failed to get VM metrics")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"data": metrics})
}

// StreamVMMetrics 流式获取虚拟机性能指标（SSE）
//
//	@Summary	Stream virtual machine metrics
//	@Tags		VM
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Param		vm_name			path		string	true	"VM Name"
//	@Param		interval		query		int		false	"Interval in seconds"	default(5)
//	@Success	200				{string}	string	"text/event-stream"
//	@Router		/connections/{connection_id}/vms/{vm_name}/metrics/stream [get]
func (h *VMHandler) StreamVMMetrics(c *gin.Context) {
	connID := c.Param("connection_id")
	vmName := c.Param("vm_name")

	intervalStr := c.DefaultQuery("interval", "5")
	interval, err := strconv.Atoi(intervalStr)
	if err != nil || interval < 1 {
		interval = 5
	}

	// 设置 SSE 响应头
	c.Header("Content-Type", "text/event-stream")
	c.Header("Cache-Control", "no-cache")
	c.Header("Connection", "keep-alive")
	c.Header("X-Accel-Buffering", "no")

	// 启动指标流
	metricsCh, err := h.vmService.StreamVMMetrics(
		c.Request.Context(),
		connID,
		vmName,
		time.Duration(interval)*time.Second,
	)
	if err != nil {
		h.logger.WithError(err).Error("Failed to stream metrics")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// 流式发送数据
	c.Stream(func(w io.Writer) bool {
		select {
		case metrics, ok := <-metricsCh:
			if !ok {
				return false
			}
			c.SSEvent("metrics", metrics)
			return true
		case <-c.Request.Context().Done():
			return false
		}
	})
}

// ConnectionHandler 连接处理器
type ConnectionHandler struct {
	connMgr domain.ConnectionManager
	logger  *logrus.Logger
}

func NewConnectionHandler(connMgr domain.ConnectionManager, logger *logrus.Logger) *ConnectionHandler {
	return &ConnectionHandler{
		connMgr: connMgr,
		logger:  logger,
	}
}

// Connect 建立连接
//
//	@Summary	Connect to libvirt
//	@Tags		Connection
//	@Param		request	body		ConnectRequest	true	"Connection request"
//	@Success	201		{object}	map[string]string
//	@Router		/connections [post]
func (h *ConnectionHandler) Connect(c *gin.Context) {
	var req ConnectRequest

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	opts := &domain.ConnectionOptions{
		ReadOnly: req.ReadOnly,
		Auth:     req.Auth,
		TLS:      req.TLS,
	}

	connID, err := h.connMgr.Connect(c.Request.Context(), req.URI, opts)
	if err != nil {
		h.logger.WithError(err).Error("Failed to connect")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{
		"connection_id": connID,
		"message":       "Connected successfully",
	})
}

// ListConnections 列出所有连接
//
//	@Summary	List all connections
//	@Tags		Connection
//	@Success	200	{array}	domain.ConnectionInfo
//	@Router		/connections [get]
func (h *ConnectionHandler) ListConnections(c *gin.Context) {
	connections, err := h.connMgr.ListConnections(c.Request.Context())
	if err != nil {
		h.logger.WithError(err).Error("Failed to list connections")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"data":  connections,
		"count": len(connections),
	})
}

// Disconnect 断开连接
//
//	@Summary	Disconnect from libvirt
//	@Tags		Connection
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Success	200				{object}	map[string]string
//	@Router		/connections/{connection_id} [delete]
func (h *ConnectionHandler) Disconnect(c *gin.Context) {
	connID := c.Param("connection_id")

	if err := h.connMgr.Disconnect(c.Request.Context(), connID); err != nil {
		h.logger.WithError(err).Error("Failed to disconnect")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Disconnected successfully"})
}

// GetCapabilities 获取能力信息
//
//	@Summary	Get hypervisor capabilities
//	@Tags		Connection
//	@Param		connection_id	path		string	true	"Connection ID"
//	@Success	200				{object}	domain.Capabilities
//	@Router		/connections/{connection_id}/capabilities [get]
func (h *ConnectionHandler) GetCapabilities(c *gin.Context) {
	connID := c.Param("connection_id")

	caps, err := h.connMgr.GetCapabilities(c.Request.Context(), connID)
	if err != nil {
		h.logger.WithError(err).Error("Failed to get capabilities")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"data": caps})
}
